/* $Header: wkfileutil.c,v 2.2 01/10/02 10:32:12 przybyls Exp $ */

/***********************************************************************/
/* MODULE NAME: wkfileutil                                             */
/* ============                                                        */
/*                                                                     */
/* Author: Tom Przybylski                                              */
/*         John DeGood                                                 */
/*                                                                     */
/* MODULE PURPOSE:  This module contains utilities used for loading    */
/*   and storing workfiles.  Some of these routines are also used by   */
/*   the startup module during instrument power-on and configuration.  */
/*                                                                     */
/***********************************************************************/
/*              Copyright Hewlett-Packard Co. 1991-1992                */
/***********************************************************************/

/* global include files */
#include <typedefs.h>
#include <pcb_defs.h>
#include <string.h>
#include <error.h>
#include <p_wkfile.h>
#include <p_status.h>
#include <p_ui.h>
#include <wkfile.h>
#include <ramps.h>
#include <zone_config.h>
#include <zone_status.h>
#include <status.h>
#include <sig_types.h>
#include <sigpath.h>
#include <oven.h>
#include <method.h>
#include <detector.h>
#include <mio.h>
#include <cmd_set.h>
#include <hostutil.h>
#include <wkfutil.h>
#include <display.h>
#include <valve_ui.h>
#include <exception.h>
#include <err_handler.h>
#include <det_ui.h>
#include <zone_ui.h>
#include <als_ui.h>
#include <config.h>
#include <kbd_ui.h>
#include <meth_config.h>
#include <valve.h>

/* global variables */

/* static variables */

/* static prototypes */
static INT16 WkfileConfigLength(BIT8 *p, INT16 len);
static void ClearCheckArea(void);
static UI_ERR CheckCheckArea(void);


typedef void (* const LOAD)(const void *param);

typedef struct
{
        const EXCEPTION exception;
        LOAD  func;
        const void *param;
} PF_DEFAULTS_ENTRY;

static const PF_DEFAULTS_ENTRY PFDefaultsTable[] =
{
   { CRYO_MISMATCH,                (LOAD)SetCryoPFDefaultSetpts,   (void *)pOVEN_TEMP },
   { F_INLET_CRYO_MISMATCH,        (LOAD)SetCryoPFDefaultSetpts,   (void *)pFRONT_INLET_TEMP },
   { B_INLET_CRYO_MISMATCH,        (LOAD)SetCryoPFDefaultSetpts,   (void *)pBACK_INLET_TEMP },
   { AUX1_CRYO_MISMATCH,           (LOAD)SetCryoPFDefaultSetpts,   (void *)pAUX_1_TEMP },
   { AUX1_CRYO_MISMATCH,           (LOAD)SetCryoPFDefaultSetpts,   (void *)pAUX_2_TEMP },

   { F_OEM_DET_CFG_CHGD,           SetDetDefaultSetpts,            (void *)FRONT }, /* also resets OEM zones & pneu !! */
   { B_OEM_DET_CFG_CHGD,           SetDetDefaultSetpts,            (void *)BACK },  /* also resets OEM zones & pneu !! */

   { FRNT_DET_TYPE_MISMATCH,       SetDetDefaultSetpts,            (void *)FRONT },
   { FRNT_DET_TYPE_MISMATCH,       (LOAD)SetZonePFDefaultSetpts,   (void *)pFRONT_DET_TEMP },
   { FRNT_DET_TYPE_MISMATCH,       (LOAD)LoadDefaultDetSetpts,     (void *)&Inst_Status.Pneu.Frnt_Detector },
   { BACK_DET_TYPE_MISMATCH,       SetDetDefaultSetpts,            (void *)BACK },
   { BACK_DET_TYPE_MISMATCH,       (LOAD)SetZonePFDefaultSetpts,   (void *)pBACK_DET_TEMP },
   { BACK_DET_TYPE_MISMATCH,       (LOAD)LoadDefaultDetSetpts,     (void *)&Inst_Status.Pneu.Back_Detector },

   { FRNT_INLET_TYPE,              (LOAD)SetZonePFDefaultSetpts,   (void *)pFRONT_INLET_TEMP },
   { FRNT_INLET_TYPE,              (LOAD)SetDefaultVentConfig,     (void *)&Inst_Status.Pneu.Frnt_Inlet         },
   { FRNT_INLET_TYPE,              (LOAD)LoadDefaultInletSetpts,   (void *)&Inst_Status.Pneu.Frnt_Inlet         },
   { FRNT_INLET_EPC,               (LOAD)LoadDefaultInletSetpts,   (void *)&Inst_Status.Pneu.Frnt_Inlet         },
   { FRNT_INLET_RANGE,             (LOAD)LoadDefaultInletSetpts,   (void *)&Inst_Status.Pneu.Frnt_Inlet         },

   { BACK_INLET_TYPE,              (LOAD)SetZonePFDefaultSetpts,   (void *)pBACK_INLET_TEMP },
   { BACK_INLET_TYPE,              (LOAD)SetDefaultVentConfig,     (void *)&Inst_Status.Pneu.Back_Inlet         },
   { BACK_INLET_TYPE,              (LOAD)LoadDefaultInletSetpts,   (void *)&Inst_Status.Pneu.Back_Inlet         },
   { BACK_INLET_EPC,               (LOAD)LoadDefaultInletSetpts,   (void *)&Inst_Status.Pneu.Back_Inlet         },
   { BACK_INLET_RANGE,             (LOAD)LoadDefaultInletSetpts,   (void *)&Inst_Status.Pneu.Back_Inlet         },

   { FRNT_DET_EPC,                 (LOAD)LoadDefaultDetSetpts,     (void *)&Inst_Status.Pneu.Frnt_Detector      },
   { FRNT_DET_FUEL_RANGE,          (LOAD)LoadDefaultDetSetpts,     (void *)&Inst_Status.Pneu.Frnt_Detector      },
   { FRNT_DET_UTIL_RANGE,          (LOAD)LoadDefaultDetSetpts,     (void *)&Inst_Status.Pneu.Frnt_Detector      },
   { FRNT_DET_MUG_RANGE,           (LOAD)LoadDefaultDetSetpts,     (void *)&Inst_Status.Pneu.Frnt_Detector      },

   { BACK_DET_EPC,                 (LOAD)LoadDefaultDetSetpts,     (void *)&Inst_Status.Pneu.Back_Detector      },
   { BACK_DET_FUEL_RANGE,          (LOAD)LoadDefaultDetSetpts,     (void *)&Inst_Status.Pneu.Back_Detector      },
   { BACK_DET_UTIL_RANGE,          (LOAD)LoadDefaultDetSetpts,     (void *)&Inst_Status.Pneu.Back_Detector      },
   { BACK_DET_MUG_RANGE,           (LOAD)LoadDefaultDetSetpts,     (void *)&Inst_Status.Pneu.Back_Detector      },

   { AUX_1_MISMATCH,               (LOAD)SetZonePFDefaultSetpts,   (void *)pAUX_1_TEMP },
   { AUX_2_MISMATCH,               (LOAD)SetZonePFDefaultSetpts,   (void *)pAUX_2_TEMP },
   { AUX_3_TYPE,                   (LOAD)LoadDefaultAuxSetpts,     (void *)&Inst_Status.Pneu.Aux.Aux_3          },
   { AUX_3_RANGE,                  (LOAD)LoadDefaultAuxSetpts,     (void *)&Inst_Status.Pneu.Aux.Aux_3          },

   { AUX_4_TYPE,                   (LOAD)LoadDefaultAuxSetpts,     (void *)&Inst_Status.Pneu.Aux.Aux_4          },
   { AUX_4_RANGE,                  (LOAD)LoadDefaultAuxSetpts,     (void *)&Inst_Status.Pneu.Aux.Aux_4          },

   { AUX_5_TYPE,                   (LOAD)LoadDefaultAuxSetpts,     (void *)&Inst_Status.Pneu.Aux.Aux_5          },
   { AUX_5_RANGE,                  (LOAD)LoadDefaultAuxSetpts,     (void *)&Inst_Status.Pneu.Aux.Aux_5          }


};

/***********************************************************************/

void SavePwrFailInstConfig(void)
/*
** Called only once during startup.  Saves old config in "check area"
** for later use by InitializeMethod() and also to initialize the "gccw"
** structure before a method download, check, and install.
**
** Saves "user config" as well as "hardware config" parameters.  Only
** the "hardware config" values are checked for changes after a powerfail,
** but both the "hardware config" and "user config" values are used
** when initializing the "gccw" structure before a method download, check,
** and install.
**
** The ALS config values will be garbage at poweron because 1) they are
** not saved in the pfail section of RAM and 2) we can't tell if the
** ALS is present until the instrument comes completely up.  It doesn't
** matter because we don't need to do anything about ALS mismatches at
** poweron anyway.  The ALS configuration info is acquired here only for
** initializing the "gccw" structure before method download, check, and
** install.
*/
{
        INT16 i;
        POSITION pos;
        BIT8 chan;
        BIT8 gas_num;

        gccw.OvenType = GetZoneType(pOVEN_TEMP);
        gccw.OvenMax = GetOvenMax();
        gccw.CryoType = GetCryoType(pOVEN_TEMP);
        gccw.MioBdPresence = FALSE;
        gccw.EpcBdPresence = (IamAdirtball()) ? FALSE : TRUE;
        gccw.AlsPowerSupply = HaveAlsPowerSupply();
        gccw.AlsFrInjector = AnyFrAlsInjector();
        gccw.AlsBkInjector = AnyBkAlsInjector();
        gccw.AlsTray= AnyAlsTray();
        gccw.AlsHadPowerSupply = TRUE;

        for (i = 0; i < 2; i++)
        {
                gccw.DetectorType[i] = GetDetectorType((POSITION)i);
                gccw.Electrometer[i] = GetElectrometerType((POSITION)i);
                gccw.AuxType[i] = GetAuxType(i+1);
        }

        /* Transmit the cryo, heater, and sensor presence for the
           inlet and auxes, and heater and sensor only for the oven
           and detectors */
        gccw.ZonePresence[ OVEN_ZONE ] = (BIT8)GetTempZonePresence( pOVEN_TEMP );
        gccw.ZonePresence[ DETA_ZONE ] = (BIT8)GetTempZonePresence( pFRONT_DET_TEMP );
        gccw.ZonePresence[ DETB_ZONE ] = (BIT8)GetTempZonePresence( pBACK_DET_TEMP );
        gccw.ZonePresence[ INJA_ZONE ] = GetZonePresence( pFRONT_INLET_TEMP );
        gccw.ZonePresence[ INJB_ZONE ] = GetZonePresence( pBACK_INLET_TEMP );
        gccw.ZonePresence[ AUXA_ZONE ] = GetZonePresence( pAUX_1_TEMP );
        gccw.ZonePresence[ AUXB_ZONE ] = GetZonePresence( pAUX_2_TEMP );

        for (i = 0; i < 8; i++)
        {
                gccw.ValveType[i] = GetValveType(i+1);
                gccw.ValveLoopVolume[i] = GetValveLoopVolume(i+1);
                gccw.ValveInlet[i] = GetValveInlet(i+1);
                gccw.MultiTime[i] = GetMultiTime();
                gccw.InvertBcd[i] = GetInvertBcd();
        }

        /*   CPF */
        for (pos = FRONT; pos < NULL_POSITION; pos++)
        {

           /* set inlet title */
           gccw.CPFInletTitlePresence[pos] = GetCPFInletTitlePresence(pos);
           if( gccw.CPFInletTitlePresence[pos] == TRUE )
           {
             StrNCpy(gccw.CPFInletTitle[pos], GetCPFInletTitle(pos), INLET_NAME_SIZE);
           };

           /* set detector title */
           gccw.CPFDetTitlePresence[pos] = GetCPFDetTitlePresence(pos);
           if( gccw.CPFDetTitlePresence[pos] == TRUE )
           {
             StrNCpy(gccw.CPFDetTitle[pos], GetCPFDetTitle(pos),DET_NAME_SIZE);
           };

           /* set CPF Det Pneu */
           gccw.CPFDetPneuPresence[pos] = GetCPFDetPneuPresence(pos);
           if(gccw.CPFDetPneuPresence[pos] == TRUE)
           {
               /* check for gas presence */
               for( gas_num = 1; gas_num <= 3 ; gas_num++ )
               {
                  gccw.CPFDetGasPresence[pos][gas_num] =
                                         GetCPFDetGasPresence(pos,gas_num);
               }
           };

           /* set OIM board config */
           gccw.CPFOIMPresence[pos] = GetCPFOIMPresence(pos);
           if( gccw.CPFOIMPresence[pos] == TRUE )
           {
              for(chan = 1;chan <=4;chan++)
              {
                 gccw.CPFCtlNumBits[pos][chan] = GetCPFCtlNumBits(pos,chan);
              }
           }
        }

        /*   OEM */
    for (pos = FRONT; (U_INT16)pos < 2; pos = (POSITION)((U_INT16)pos + 1) )
    {

     switch  ( gccw.DetectorType[(BIT8)pos])
     {
        case OEM_AIB:
        case OEM_FID:

                    gccw.CPFDetTitlePresence[pos] = 1 ;
                for( gas_num = 1; gas_num <= LAST_OEM_GAS ; gas_num++ )
                {
                   gccw.OEMDetGasModes[pos][gas_num] =  (INT32) OEMDetFritFlags[pos][gas_num-1];
                };

                for (i = 0; i < DET_NAME_SIZE+1; i++  )
                {
                   gccw.OEMCtlStates[pos][i] = 0 ; /* need this since "|=" below will only SET bits */
                                                        /* only 1st two cells of F,B arrays are needed  */
                }


                for( chan  = 1; chan  <= LAST_OEM_CTRL ; chan ++ )
                {
                   /* label presence is bit packed; chnls 1..8 in array[.][0], chnls 9..16 in array[.][1], ... */

                   gccw.OEMCtlStates[pos][(chan-1) >> 3] |= GetOEMCtlPresence(pos,chan) << (( chan-1) % 8) ;


                   if ( ( chan <= LAST_OEM_ONOFF  ) && ( GetOEMCtlPresence(pos,chan) ) )
                   {
                      gccw.OEMCtlPulseLens[pos][chan-1] = GetOEMCtlPulseLen( pos, chan ) ;
                   }
                };

                break;

        default:
                break;
     }

    }

    SavePneuConfigInWkfile();
}

/***********************************************************************/

void InitializeMethod(void)
/*
** Called only once during startup.
** Defaults setpoints as necessary because of HW changes during powerfail.
**
** RETURNS:  OK            - no changes necessary
**           PARAM_CHANGED - one or more changes made
*/
{
        U_INT16 i;

        /* if there was a powerfail memory reset the default method was loaded so there is nothing to do */
        if (PF_Reset == FALSE)
        {
                /*
                ** Compare the current HW config against that in the "check area",
                ** which contains the HW config at the time of the last powerfail.
                */
                if (CheckCheckArea() != OK)
                {
                        /*
                        ** For each entry in the powerfail defaults table, if the exception is TRUE then
                        ** execute the associated function to default the appropriate setpoints.
                        */
                        for (i = 0; i < ( sizeof(PFDefaultsTable) / sizeof(PF_DEFAULTS_ENTRY) ); i++)
                        {
                                if ( TestForException(PFDefaultsTable[i].exception) )
                                {
                                        PFDefaultsTable[i].func(PFDefaultsTable[i].param);
                                }

                                /* Set signal setpts to PF defaults for missing hw */
                                ResolveSigPathPowerOnSetpts();
                        }

                    /* cases where the column needs to be defaulted if hardware changed */
                    /* through the source/outlet connections cannot be done inside the  */
                    /* PF_Defaults table, so do them here                               */

                    DefaultColumnIfHardwareChanged( &Inst_Status.Pneu.Column_1 );
                    DefaultColumnIfHardwareChanged( &Inst_Status.Pneu.Column_2 );

                    for (i = 1; i <= 8; i++) /* Gsv1 & Gsv2 not set yet, step through all valves */
                    {
                       DefaultGsvInletIfHwChanged ((U_INT8) i);
                    }

                }
        }
}

/***********************************************************************/

void UpdateInstStatus (void)
/*
 * Called during startup and after each "load workfile".
 * Forces Active_Wkfile setpoints into working copies and/or hardware.
 */
{
        /* Set initial values for oven and thermal zones. */
        UpdateZoneInitValues();

        /* Copy Active Workfile setpoints to SigPath working copies. */
        UpdateSigPathStatus();

        /* Copy Active Workfile setpoints to Zones working copies. */
        UpdateOven_ZoneStatus();

        /* Make valves agree with workfile ON/OFF values        */
        ResetValveState();

        /* Jam the filters for all the ramps. */
        SetInitValues();

        /* Update pneumatics status structure with Active_Wkfile values. */
        MethodStatusStructUpdate();

        /* restore the CPF control line values to Active_Wkfile values */
        UpdateCPFCtlValues ();


        /*
        ** Copy Active Workfile setpoints to detector hardware.
        ** NOTE:  This must appear *after* the pneumatic and zone updates
        ** have completed because the detector state machines make decisions
        ** based on temperature and flow setpoints.
        */
        UpdateDetStatus();
}

/* DoCmdPreFunction - called before processing any params of a datacom command */
UI_ERR DoCmdPreFunction(const METHCMD *cmd)
{
        return cmd->preFunction(cmd->setpoint);
}

/***********************************************************************/

/* DoCmdPostFunction - called after processing all params of a datacomm command */
UI_ERR DoCmdPostFunction(const METHCMD *cmd)
{
        return cmd->postFunction(cmd->setpoint);
}

/***********************************************************************/

UI_ERR GetWkfileParam(BIT8 *param, const METHCMD *cmd, int index)
/*
 * Used to get a single parameter for a datacomm command.
 *
 * returns:     OK for success, reason code if error
 *              *param = formatted Active_Wkfile parameter value
 */
{
        METHCMD_ENTRY *entry;
        INT32 setpt;

        /* retrieve table entry if index within range */
        if ( (index < 0) || (index > cmd->maxindex) )
        {
                return NUM_OF_PARAM;
        }
        else
        {
                entry = (METHCMD_ENTRY *) &(cmd->array[index]);
        }

        /* call "Get" function */
        setpt = entry->getFunction(cmd->setpoint, entry->selector);

        /* format result into output string */
        switch (entry->format)
        {
        case METH_ON_OFF:  /* returns 0 if OFF, 1 if any other enumeration value */
                param += PutIntParam(((ON_OFF)setpt == OFF) ? 0 : 1, param, 0);
                break;

        case METH_INT0:
                param += PutIntParam(setpt, param, 0);
                break;

        case METH_INT1:
                param += PutIntParam(setpt, param, 1);
                break;

        case METH_INT2:
                param += PutIntParam(setpt, param, 2);
                break;

        case METH_INT3:
                param += PutIntParam(setpt, param, 3);
                break;

        case METH_FILL6:  /* use for date formats, e.g. HHMMSS or DDMMYY */
                param += IntToDecFilled(setpt, param, 6);
                break;

        case METH_HEX:
                param = (BIT8 *)FormatHexadecimal((U_INT32)setpt, (BIT8 *)param, 0);
                break;

        case METH_STR:
                /* strcpy the string pointed to by setpt */
                while ((*param++ = *((BIT8 *)setpt++)) != '\0')
                {
                        /* empty body */
                }
                break;

        case METH_QSTR:
                /*
                ** WARNING: this format should not be used in method commands,
                ** as the method format will be confused by the embedded quotes
                */
                /* beginning quote */
                *param++ = '"';

                /* strcpy the string pointed to by setpt */
                while ((*param++ = *((BIT8 *)setpt++)) != '\0')
                {
                        /* empty body */
                }

                /* overwrite string terminator with ending quote */
                *(param - 1)  = '"';

                /* append string terminator */
                *param = '\0';
                break;

        case METH_CSTR:
                /*
                ** this format may be used in method commands,
                ** it uses the curly brackets for quoting strings {str 1}
                */
                /* beginning bracket */
                *param++ = '{';

                /* strcpy the string pointed to by setpt */
                while ((*param++ = *((BIT8 *)setpt++)) != '\0')
                {
                        /* empty body */
                }

                /* overwrite string terminator with ending bracket */
                *(param - 1)  = '}';

                /* append string terminator */
                *param = '\0';
                break;

        default:  /* internal error */
                return INVALID_PARAM;
        }
        *param = '\0';  /* append NULL */

        return OK;
}

/***********************************************************************/

UI_ERR SetWkfileParam(BIT8 *param, const METHCMD *cmd, int index)
/*
 * Used to set a single workfile parameter for a datacomm command.
 *
 * returns:     OK for success, reason code if error
 *              *param = formatted Active_Wkfile parameter value
 */
{
        METHCMD_ENTRY *entry;
        UI_ERR ui_err;
        INT32 setpt;

        /* retrieve table entry if index within range */
        if ( (index < 0) || (index > cmd->maxindex) )
        {
                return NUM_OF_PARAM;
        }
        else
        {
                entry = (METHCMD_ENTRY *) &(cmd->array[index]);
        }

        /* get setpoint value from input string */
        switch (entry->format)
        {
        case METH_INT0:
        case METH_FILL6:  /* use for date formats, e.g. HHMMSS or DDMMYY */
                if ((ui_err = DecToInt(param, 0, &setpt)) != OK)
                {
                        return ui_err;
                }
                break;

        case METH_INT1:
                if ((ui_err = DecToInt(param, 1, &setpt)) != OK)
                {
                        return ui_err;
                }
                break;

        case METH_INT2:
                if ((ui_err = DecToInt(param, 2, &setpt)) != OK)
                {
                        return ui_err;
                }
                break;

        case METH_INT3:
                if ((ui_err = DecToInt(param, 3, &setpt)) != OK)
                {
                        return ui_err;
                }
                break;

        case METH_ON_OFF:
                /* validate ON_OFF value here instead of in each set function */
                if (*param != '1' && *param != '0')
                {
                        return INVALID_PARAM;
                }

                setpt = *param - '0';
                break;

        case METH_HEX:
                if ((ui_err = HexToInt(param, (U_INT32 *)&setpt)) != OK)
                {
                        return ui_err;
                }
                break;

        case METH_STR:
        case METH_QSTR:
        case METH_CSTR:
                /* the setpoint is simply the parameter string pointer */
                setpt = (INT32)param;
                break;

        default:  /* internal error */
                return INVALID_PARAM;
        }

        /* call "Set" function */
        return entry->setFunction(cmd->setpoint, setpt, entry->selector);
}

/***********************************************************************/

static INT16 WkfileConfigLength(BIT8 *p, INT16 len)
/*
** Returns length of the "config section" of a method.
**
** WARNINGS: 1) *p MUST have room for a string terminator to be appended at (*p + len).
**           2) the workfile separator must exactly match the literal string "CCCCCE".
*/
{
        BIT8 *s;

        /* append string terminator at end so strstr() doesn't search past (p + len) */
        *(p + len) = '\0';

        /* do string search for the "GCCE" method separator */
        s = (BIT8 *)strstr( (char *)p, "CCCCCE");

        /* return length of config section, or "0" if none is found */
        return ((s == NULL) ? 0 : (s - p));
}

/***********************************************************************/

static void ClearCheckArea(void)
/*
** Initialize the check area to the current configuration so methods
** which are missing config parameters won't default to garbage.
*/
{
        SavePwrFailInstConfig();
}

/***********************************************************************/

static UI_ERR CheckCheckArea(void)
/*
** Check method config against current instrument config
*/
{
        CheckDetConfig();
        CheckPneuConfigInWkfile();   /* Inlet, Det, Aux, and Column config checking */
        CheckCPFInletConfigInWkfile();  /* CPF Inlet title checking */
        CheckCPFDetConfigInWkfile();  /* CPF and OIM checking */
    CheckOEMDetConfigInWkfile();  /* OEM checking */
        CheckValveConfig();
        CheckZoneConfigInWkfile();
        CheckAlsConfig();            /* Sampler config checking */

        /* REVISIT - add the rest of the checks */

        return ( (TestForMethodWarning()) ? NOT_COMPATIBLE : OK );
}

/***********************************************************************/

UI_ERR CheckWorkfile(BIT8 *p, U_INT16 length, BIT8 *crc, WKFILE_CONTENTS contents,
                     U_INT16 chan)
/*
 * Test "check area" setpoints against hardware configuration and
 * "fix" if necessary.
 *
 * RETURNS:     OK              - no changes necessary
 *              PARAM_CHANGED   - one or more changes made
 */
{
        (void) contents;

        /* clear any old exceptions from prior calls to this function */
        ClearMethodWarnings();

        /* clear config check area by filling it with the current instrument config */
        ClearCheckArea();

        /* check method CRC */
        if (CheckWkfileCrc(p, length, crc) != OK)
        {
                SetNewException(CRC_MISMATCH, 0, 0);
        }

        /* execute config portion of workfile download buffer, installing config values into check area */
        InstallWkFile(p, WkfileConfigLength(p, length), chan);

        /* check workfile config against current config and set exceptions if mismatches are found */
        return CheckCheckArea();
}

/***********************************************************************/

void UpdateMethodModified (U_INT16 port)
{
  U_INT16 i;

  for (i = 0; i < 2; i++)
  {
     Parameter_Modified[i].bits.meth_load = 1;
     if (port == i)
     {
        Parameter_Modified2[i].bits.gc_param = 0;
        Parameter_Modified2[i].bits.meth_load = 0;
     }
     else
     {
        Parameter_Modified2[i].bits.meth_load = 1;
     }
  }
  Method_Dirty = FALSE;
}

/***********************************************************************/

void UpdateMethodDirectory (U_INT16 port)
{
/* used by method store, method delete */
  U_INT16 i;

  for (i = 0; i < 2; i++)
  {
     if (port == i)
     {
        Parameter_Modified2[i].bits.meth_directory = 0;
     }
     else
     {
        Parameter_Modified2[i].bits.meth_directory = 1;
     }
  }
}

/***********************************************************************/

void InstallWorkfile(BIT8 *p, U_INT16 length, BIT8 *crc, WKFILE_CONTENTS contents, U_INT16 chan)
/*
 * Move a workfile image from the check area to the Active_Wkfile and
 * update working setpoint copies.
 */
{
        INT16 len;

        /* This is a redundant call to CheckWorkfile(), in case the datacomm user didn't do it. */
        (void)CheckWorkfile(p, length, crc, contents, chan);

        /* begin pneumatics "install mode" */
        BeginMethodInstall();

        /* install non-HW sections of the config check area */
        InstallPneuConfigInWkfile();

        (void) TakeThisOvenMaxAndShoveIt( gccw.OvenMax );

        TakeThisValveConfigAndShoveIt();

        /* REVISIT - add the rest of the user config sections */

        /* execute the setpoint section of the workfile download buffer */
        len = WkfileConfigLength(p, length);
        InstallWkFile(p + len, length - len, chan);

        /* Copy the setpoints from the Active Workfile to the status (working) copies and HW. */
        UpdateInstStatus();

        /* force the display to update in case we are displaying something like ALS setpoints */
        ForceKeyboardDisplayRefresh();

        /* end pneumatics "install mode" */
        EndMethodInstall();
}
